﻿using System;
using System.Collections.Generic;

namespace FySystem.IOTFlow
{
    /// <summary>
    /// 对数据进行打包用的流
    /// </summary>
    public class PackingFlow
    {
        private List<byte> _arr = null;

        /// <summary>
        /// 是否为大端，由于大多数物联网协议都是大端，所以默认为true
        /// </summary>
        public bool IsBigEndian { get; set; } = true;

        /// <summary>
        /// 创建流实例
        /// </summary>
        /// <param name="isBigEndian"></param>
        public PackingFlow(bool isBigEndian)
        {
            _arr = new List<byte>();
            IsBigEndian = isBigEndian;
        }

        /// <summary>
        /// 写入一个字节
        /// </summary>
        /// <param name="b"></param>
        public void WriteByte(byte b)
        {
            _arr.Add(b);
        }

        /// <summary>
        /// 写入多个字节
        /// </summary>
        /// <param name="b"></param>
        public void WriteBytes(byte[] b)
        {
            _arr.AddRange(b);
        }

        /// <summary>
        /// 写入多个字节
        /// </summary>
        /// <param name="b"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        public void WriteBytes(byte[] b, int offset, int length)
        {
            try
            {
                int endIndex = offset + length;
                for (int i = offset; i < endIndex; i++)
                {
                    _arr.Add(b[i]);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 反向写入多个字节
        /// </summary>
        /// <param name="b"></param>
        public void WriteReverseBytes(byte[] b)
        {
            try
            {
                for (int i = b.Length - 1; i >= 0; i--)
                {
                    _arr.Add(b[i]);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 由于C#为小端，所以当流为大端的时候，就要反过来写入，否则按照顺序写入
        /// </summary>
        /// <param name="b"></param>
        private void WriteBytesWithEndian(byte[] b)
        {
            try
            {
                if (IsBigEndian)
                    WriteReverseBytes(b);
                else
                    WriteBytes(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入无符号2字节整数
        /// </summary>
        /// <param name="val"></param>
        public void WriteUShort(ushort val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                WriteBytesWithEndian(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入有符号2字节整数
        /// </summary>
        /// <param name="val"></param>
        public void WriteShort(short val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                WriteBytesWithEndian(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入无符号4字节整数
        /// </summary>
        /// <param name="val"></param>
        public void WriteUInt(uint val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                WriteBytesWithEndian(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入有符号4字节整数
        /// </summary>
        /// <param name="val"></param>
        public void WriteInt(int val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                WriteBytesWithEndian(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入无符号8字节整数
        /// </summary>
        /// <param name="val"></param>
        public void WriteULong(ulong val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                WriteBytesWithEndian(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 写入有符号8字节整数
        /// </summary>
        /// <param name="val"></param>
        public void WriteLong(long val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                WriteBytesWithEndian(b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入一个字节
        /// </summary>
        /// <param name="index"></param>
        /// <param name="b"></param>
        public void InsertByte(int index, byte b)
        {
            try
            {
                _arr.Insert(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入多个字节
        /// </summary>
        /// <param name="index"></param>
        /// <param name="b"></param>
        public void InsertBytes(int index, byte[] b)
        {
            try
            {
                _arr.InsertRange(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 反向插入多个字节
        /// </summary>
        /// <param name="b"></param>
        public void InsertReverseBytes(int index, byte[] b)
        {
            try
            {
                for (int i = b.Length - 1; i >= 0; i--)
                {
                    _arr.Insert(index, b[i]);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 根据大端还是小端插入多个字节
        /// </summary>
        /// <param name="index"></param>
        /// <param name="b"></param>
        private void InsertBytesWithEndian(int index, byte[] b)
        {
            try
            {
                if (IsBigEndian)
                    _arr.InsertRange(index, b);
                else
                    InsertReverseBytes(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入无符号2字节整数
        /// </summary>
        /// <param name="index"></param>
        /// <param name="val"></param>
        public void InsertUShort(int index, ushort val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                InsertBytesWithEndian(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入有符号2字节整数
        /// </summary>
        /// <param name="index"></param>
        /// <param name="val"></param>
        public void InsertShort(int index, short val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                InsertBytesWithEndian(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入无符号4字节整数
        /// </summary>
        /// <param name="index"></param>
        /// <param name="val"></param>
        public void InsertUInt(int index, uint val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                InsertBytesWithEndian(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入有符号4字节整数
        /// </summary>
        /// <param name="index"></param>
        /// <param name="val"></param>
        public void InsertInt(int index, int val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                InsertBytesWithEndian(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入无符号8字节整数
        /// </summary>
        /// <param name="index"></param>
        /// <param name="val"></param>
        public void InsertULong(int index,ulong val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                InsertBytesWithEndian(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 在指定位置插入有符号8字节整数
        /// </summary>
        /// <param name="index"></param>
        /// <param name="val"></param>
        public void InsertLong(int index,long val)
        {
            try
            {
                byte[] b = BitConverter.GetBytes(val);
                InsertBytesWithEndian(index, b);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
